package imghelper

import (
	"errors"
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"os"

	"github.com/nfnt/resize"
	"golang.org/x/image/bmp"
)

type ImageHandler struct {
	In  image.Image
	Fm  string
	Out io.Writer
}

func NewImageHandler(src io.Reader, out io.Writer) (h *ImageHandler, err error) {
	origin, fm, err := image.Decode(src)
	if err != nil {
		return
	}
	return &ImageHandler{
		In:  origin,
		Fm:  fm,
		Out: out,
	}, nil
}

// 图片裁剪
func (h *ImageHandler) Clip(rect image.Rectangle, quality int) (err error) {
	switch h.Fm {
	case "jpeg":
		img := h.In.(*image.YCbCr)
		subImg := img.SubImage(rect).(*image.YCbCr)
		return jpeg.Encode(h.Out, subImg, &jpeg.Options{Quality: quality})
	case "png":
		switch h.In.(type) {
		case *image.NRGBA:
			img := h.In.(*image.NRGBA)
			subImg := img.SubImage(rect).(*image.NRGBA)
			return png.Encode(h.Out, subImg)
		case *image.RGBA:
			img := h.In.(*image.RGBA)
			subImg := img.SubImage(rect).(*image.RGBA)
			return png.Encode(h.Out, subImg)
		case *image.RGBA64:
			img := h.In.(*image.RGBA64)
			subImg := img.SubImage(rect).(*image.RGBA64)
			return png.Encode(h.Out, subImg)
		case *image.NRGBA64:
			img := h.In.(*image.NRGBA64)
			subImg := img.SubImage(rect).(*image.NRGBA64)
			return png.Encode(h.Out, subImg)
		case *image.Alpha:
			img := h.In.(*image.Alpha)
			subImg := img.SubImage(rect).(*image.Alpha)
			return png.Encode(h.Out, subImg)
		case *image.Alpha16:
			img := h.In.(*image.Alpha16)
			subImg := img.SubImage(rect).(*image.Alpha16)
			return png.Encode(h.Out, subImg)
		case *image.Gray:
			img := h.In.(*image.Gray)
			subImg := img.SubImage(rect).(*image.Gray)
			return png.Encode(h.Out, subImg)
		case *image.Gray16:
			img := h.In.(*image.Gray16)
			subImg := img.SubImage(rect).(*image.Gray16)
			return png.Encode(h.Out, subImg)
		case *image.CMYK:
			img := h.In.(*image.CMYK)
			subImg := img.SubImage(rect).(*image.CMYK)
			return png.Encode(h.Out, subImg)
		case *image.Paletted:
			img := h.In.(*image.Paletted)
			subImg := img.SubImage(rect).(*image.Paletted)
			return png.Encode(h.Out, subImg)
		default:
			return errors.New("ERROR FORMAT")
		}
	case "gif":
		img := h.In.(*image.Paletted)
		subImg := img.SubImage(rect).(*image.Paletted)
		return gif.Encode(h.Out, subImg, &gif.Options{})
	case "bmp":
		img := h.In.(*image.RGBA)
		subImg := img.SubImage(rect).(*image.RGBA)
		return bmp.Encode(h.Out, subImg)
	default:
		return errors.New("ERROR FORMAT")
	}
}

// 缩略图
func (h *ImageHandler) Scale(width, height, quality int) error {
	if width == 0 || height == 0 {
		width = h.In.Bounds().Max.X
		height = h.In.Bounds().Max.Y
	}
	if quality == 0 {
		quality = 100
	}
	canvas := resize.Thumbnail(uint(width), uint(height), h.In, resize.Lanczos3)

	switch h.Fm {
	case "jpeg":
		return jpeg.Encode(h.Out, canvas, &jpeg.Options{Quality: quality})
	case "png":
		return png.Encode(h.Out, canvas)
	case "gif":
		return gif.Encode(h.Out, canvas, &gif.Options{})
	case "bmp":
		return bmp.Encode(h.Out, canvas)
	default:
		return errors.New("ERROR FORMAT")
	}
}

func ImgWidthHeight(fp string) (width, height int, err error) {
	r, err := os.Open(fp)
	if err != nil {
		return
	}
	defer r.Close()
	im, _, err := image.DecodeConfig(r)
	if err != nil {
		return
	}
	width = im.Width
	height = im.Height
	return
}
